package com.yuntsg.subject_database.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.util.StringUtils;

import java.net.URL;
import java.util.*;

/**
 * 工具类的规范例子
 *
 * @author
 */
public class StringUtil {

    private static final String PLAIN_ASCII =
            "AaEeIiOoUu"    // Grave
                    + "AaEeIiOoUuYy"  // acute
                    + "AaEeIiOoUuYy"  // circumflex
                    + "AaOoNn"        // tilde
                    + "AaEeIiOoUuYy"  // umlaut
                    + "Aa"            // ring
                    + "Cc"            // cedilla
                    + "OoUu"          // double acute
            ;
    private static final String UNICODE = "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"
            + "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD"
            + "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177"
            + "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
            + "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF"
            + "\u00C5\u00E5"
            + "\u00C7\u00E7"
            + "\u0150\u0151\u0170\u0171";
    /**
     * 用于作者匹配的map
     */
    public static Map<String, String> authReplaceMap = new HashMap<>();
    /**
     * 用于期刊匹配的map
     */
    public static Map<String, String> jourReplaceMap = new HashMap<>();
    /**
     * 用于标准匹配的map
     */
    public static Map<String, String> standardReplaceMap = new HashMap<>();

    public static String re(String s) {
        return standardizeDefault(convertNonAscii(s));
    }

    public static boolean isEmpty(CharSequence cs) {
        return StringUtils.isEmpty(cs);
    }

    public static boolean isEmpty(Collection<?> collection) {
        return collection == null || collection.size() == 0;
    }

    // remove accentued from a string and replace with ascii equivalent
    public static String convertNonAscii(String s) {
        if (s == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        int n = s.length();
        for (int i = 0; i < n; i++) {
            char c = s.charAt(i);
            int pos = UNICODE.indexOf(c);
            if (pos > -1) {
                sb.append(PLAIN_ASCII.charAt(pos));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 对字符串进行默认排序
     */
    public static String sort(String str) {
        char[] chs = str.toCharArray();
        Arrays.sort(chs);
        return new String(chs);
    }

    //计算相似度
    public static float similarity(String str1, String str2, int distinceNum) {
        float similarity = 1 - (float) distinceNum / Math.max(str1.length(), str2.length());
        return similarity;
    }

    /**
     * 编辑距离，用来判断两个字符串之间变为相同所需要的操作次数，移动，增加，删除都算一次操作。
     */
    public static int edit(String str1, String str2) {
        int[][] array;
        int max1 = str1.length();
        int max2 = str2.length();
        //建立数组，比字符长度大一个空间
        array = new int[max2 + 1][max1 + 1];
        for (int i = 0; i <= max1; i++) {
            array[0][i] = i;
        }
        for (int j = 0; j <= max2; j++) {
            array[j][0] = j;
        }

        for (int i = 1; i <= max1; i++) {
            for (int j = 1; j <= max2; j++) {
                array[j][i] = levenshtein(i, j, str1.charAt(i - 1), str2.charAt(j - 1), array);
//				System.out.println("j=="+j+" i=="+i+"   "+array[j][i]);
            }
        }
//		System.out.println("*********"+array[max2][max1]);
        return array[max2][max1];
    }

    private static int levenshtein(int i, int j, char si, char sj, int[][] array) {
        int result = 0;

        if (i >= 1 && j >= 1) {
            int a = array[j - 1][i] + 1;
            int b = array[j][i - 1] + 1;
            int c = array[j - 1][i - 1] + ((si != sj) ? 1 : 0);
            result = min(a, b, c);
        }

        return result;
    }

    private static int min(int a, int b, int c) {
        int temp = a < b ? a : b;
        return temp < c ? temp : c;
    }


    /**
     * 常用中文标点符号转英文字标点符号
     *
     * @param str 原字符串
     * @return str 新字符串
     */
    public static final String cToe(String str) {
        String[] regs = {"！", "，", "。", "；", "~", "《", "》", "（", "）", "？", "”", "｛", "｝", "“", "：", "【", "】", "‘", "’",
                "!", ",", ".", ";", "`", "<", ">", "\\(", "\\)", "\\?", "\"", "\\{", "}", "\"", ":", "\\{", "}", "\'", "\'"};
        for (int i = 0; i < regs.length / 2; i++) {
            str = str.replaceAll(regs[i], regs[i + regs.length / 2]);
        }
        return str;
    }


    /**
     * 全角转半角
     */
    public static final String full2Half(String fullStr) {
        if (isEmpty(fullStr)) {
            return fullStr;
        }
        char[] c = fullStr.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] >= 65281 && c[i] <= 65374) {
                c[i] = (char) (c[i] - 65248);
                // 空格
            } else if (c[i] == 12288) {
                c[i] = (char) 32;
            }
        }
        return new String(c);
    }

    /**
     * 半角转全角
     *
     * @param halfStr
     * @return
     */
    public static final String half2Full(String halfStr) {
        if (isEmpty(halfStr)) {
            return halfStr;
        }
        char[] c = halfStr.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] == 32) {
                c[i] = (char) 12288;
            } else if (c[i] < 127) {
                c[i] = (char) (c[i] + 65248);
            }
        }
        return new String(c);
    }


    /**
     * 根据unicodeBlock方法判断是不是中文标点符号
     */
    public static boolean isCnPunc(char c) {
        java.lang.Character.UnicodeBlock ub = java.lang.Character.UnicodeBlock.of(c);
        if (ub == java.lang.Character.UnicodeBlock.GENERAL_PUNCTUATION
                || ub == java.lang.Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == java.lang.Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == java.lang.Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS
                || ub == java.lang.Character.UnicodeBlock.VERTICAL_FORMS) {
            return true;
        } else {
            return false;
        }
    }


    /**
     * 判断是不是符号类
     */
    public static boolean isSymbol(char ch) {
        if (isCnSymbol(ch)) {
            return true;
        }
        if (isEnSymbol(ch)) {
            return true;
        }

        if (0x2010 <= ch && ch <= 0x2017) {
            return true;
        }
        if (0x2020 <= ch && ch <= 0x2027) {
            return true;
        }
        if (0x2B00 <= ch && ch <= 0x2BFF) {
            return true;
        }
        if (0xFF03 <= ch && ch <= 0xFF06) {
            return true;
        }
        if (0xFF08 <= ch && ch <= 0xFF0B) {
            return true;
        }
        if (ch == 0xFF0D || ch == 0xFF0F) {
            return true;
        }
        if (0xFF1C <= ch && ch <= 0xFF1E) {
            return true;
        }
        if (ch == 0xFF20 || ch == 0xFF65) {
            return true;
        }
        if (0xFF3B <= ch && ch <= 0xFF40) {
            return true;
        }
        if (0xFF5B <= ch && ch <= 0xFF60) {
            return true;
        }
        if (ch == 0xFF62 || ch == 0xFF63) {
            return true;
        }
        if (ch == 0x0020 || ch == 0x3000) {
            return true;
        }
        return false;

    }

    /**
     * 是不是中文符号
     */
    public static boolean isCnSymbol(char ch) {
        if (0x3004 <= ch && ch <= 0x301C) {
            return true;
        }
        if (0x3020 <= ch && ch <= 0x303F) {
            return true;
        }
        return false;
    }

    /**
     * 是不是英文符号
     */
    public static boolean isEnSymbol(char ch) {

        if (ch == 0x40) {
            return true;
        }
        if (ch == 0x2D || ch == 0x2F) {
            return true;
        }
        if (0x23 <= ch && ch <= 0x26) {
            return true;
        }
        if (0x28 <= ch && ch <= 0x2B) {
            return true;
        }
        if (0x3C <= ch && ch <= 0x3E) {
            return true;
        }
        if (0x5B <= ch && ch <= 0x60) {
            return true;
        }
        if (0x7B <= ch && ch <= 0x7E) {
            return true;
        }

        return false;
    }

    /**
     * 判断是不是标点符号
     */
    public static boolean isPunctuation(char ch) {
        if (isCjkPunc(ch)) {
            return true;
        }
        if (isEnPunc(ch)) {
            return true;
        }

        if (0x2018 <= ch && ch <= 0x201F) {
            return true;
        }
        if (ch == 0xFF01 || ch == 0xFF02) {
            return true;
        }
        if (ch == 0xFF07 || ch == 0xFF0C) {
            return true;
        }
        if (ch == 0xFF1A || ch == 0xFF1B) {
            return true;
        }
        if (ch == 0xFF1F || ch == 0xFF61) {
            return true;
        }
        if (ch == 0xFF0E) {
            return true;
        }
        if (ch == 0xFF65) {
            return true;
        }

        return false;
    }

    /**
     * 英文标点符号判定
     */
    public static boolean isEnPunc(char ch) {
        if (0x21 <= ch && ch <= 0x22) {
            return true;
        }
        if (ch == 0x27 || ch == 0x2C) {
            return true;
        }
        if (ch == 0x2E || ch == 0x3A) {
            return true;
        }
        if (ch == 0x3B || ch == 0x3F) {
            return true;
        }
        return false;
    }

    static boolean isCjkPunc(char ch) {
        if (0x3001 <= ch && ch <= 0x3003) {
            return true;
        }
        if (0x301D <= ch && ch <= 0x301F) {
            return true;
        }

        return false;
    }

    //西里尔文字母转换
    public static String convertCyrilic(String message) {
        char[] abcCyr = {' ', 'а', 'б', 'в', 'г', 'д', 'ѓ', 'е', 'ж', 'з', 'ѕ', 'и', 'ј', 'к', 'л', 'љ', 'м', 'н', 'њ', 'о', 'п', 'р', 'с', 'т', 'ќ', 'у', 'ф', 'х', 'ц', 'ч', 'џ', 'ш', 'А', 'Б', 'В', 'Г', 'Д', 'Ѓ', 'Е', 'Ж', 'З', 'Ѕ', 'И', 'Ј', 'К', 'Л', 'Љ', 'М', 'Н', 'Њ', 'О', 'П', 'Р', 'С', 'Т', 'Ќ', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Џ', 'Ш', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '/', '-'};
        String[] abcLat = {" ", "a", "b", "v", "g", "d", "]", "e", "zh", "z", "y", "i", "j", "k", "l", "q", "m", "n", "w", "o", "p", "r", "s", "t", "'", "u", "f", "h", "c", ";", "x", "{", "A", "B", "V", "G", "D", "}", "E", "Zh", "Z", "Y", "I", "J", "K", "L", "Q", "M", "N", "W", "O", "P", "R", "S", "T", "KJ", "U", "F", "H", "C", ":", "X", "{", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/", "-"};
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < message.length(); i++) {
            for (int x = 0; x < abcCyr.length; x++) {
                if (message.charAt(i) == abcCyr[x]) {
                    builder.append(abcLat[x]);
                }
            }
        }
        return builder.toString();
    }

    /**
     * 将代理低区和高区全部以及私用区全部都删除掉。
     * 似乎 \pC 这个正则就包含了surrogates和私用区
     **/
    public static String replacePrivateAndSurrogate(String input) {
        String[] regexpStrArray = new String[]{"[\\ud800-\\udb7f]", "[\\udc00-\\udfff]", "[\\ue000-\\uf8ff]"};
        for (String regexpStr : regexpStrArray) {
            input = input.replaceAll(regexpStr, "");
        }
        return input;
    }

    public static String removeSympol(String alph) {
        alph = alph.replaceAll("\\pZ", "");
        return alph;
    }

    /**
     * 作者标准替换，保留空格
     */
    public static String standardizeAuthWithBlank(String input) {
        if (authReplaceMap.size() == 0) {
            mapInit();
        }
        String output = input.replaceAll("[^\\p{L}\\s]", "").replaceAll("\\s+", " ");
        for (Map.Entry<String, String> entry : authReplaceMap.entrySet()) {
//            output = output.replace(entry.getKey(), entry.getValue());
            output = StringUtils.replace(output, entry.getKey(), entry.getValue());
        }
        return output;
    }

    /**
     * 获取作者，去除掉所有的空格。
     */
    public static String standardizeAuthNoBlank(String input) {
        String output = standardizeAuthWithBlank(input).replaceAll("\\s", "");
        return output;
    }

    /**
     * 期刊标准字符替换
     */
    public static String standardizeJourWithBlank(String input) {
        if (jourReplaceMap.size() == 0) {
            mapInit();
        }
        String output = input.replaceAll("[^\\p{L}\\p{N}\\s]", "");
        for (Map.Entry<String, String> entry : jourReplaceMap.entrySet()) {
//            output = output.replace(entry.getKey(), entry.getValue());
            /**下面的方法一万次匹配比上面方法从12s降低到了1s，去掉本模块的替换则减少到0.5s左右*/
            output = StringUtils.replace(output, entry.getKey(), entry.getValue());
            //hutool的替换方法在3-4s
//            output = StrUtil.replace(output, entry.getKey(), entry.getValue());
        }
        return output;
    }

    /**
     * 期刊标准字符替换
     */
    public static String standardizeJourNoBlank(String input) {
        String output = standardizeJourWithBlank(input).replaceAll("\\s", "");
        return output;
    }

    /**
     * 功能描述:
     * 默认的字符串标准化处理程序，将希腊文，德文，法文等进行英文化处理。对全角字符转化为标准英文字符等。
     * <br>
     *
     * @author:鲍来强
     * @Author: baolaiqiang
     * @ctime:2022/2/9 13:52
     * @modifyTime: 2022/2/9 13:52
     * @modifyDescription: <br>
     */
    public static String standardizeDefault(String input) {
        if (jourReplaceMap.size() == 0) {
            mapInit();
        }
        input = replacePrivateAndSurrogate(input);
        for (Map.Entry<String, String> entry : standardReplaceMap.entrySet()) {
//            input = input.replace(entry.getKey(), entry.getValue());
            input = StringUtils.replace(input, entry.getKey(), entry.getValue());
        }
        input = input.replaceAll("\\s+", " ");
        return input;
    }

    private static void mapInit() {
        readReplaceDict("dict/auth-replace.txt", authReplaceMap);
        readReplaceDict("dict/jour-replace.txt", jourReplaceMap);
        readReplaceDict("dict/standard-replace.txt", standardReplaceMap);
    }

    private static void readReplaceDict(String path, Map<String, String> replaceMap) {
        System.out.println("读取" + path + "...");
        URL url = StringUtil.class.getClassLoader().getResource(path);
        if (url == null) {
            System.out.println("文件不存在...");
            return;
        }
        List<String> lineList = FileUtil.readLines(url, "utf8");
        System.out.println("共有:" + lineList.size() + "行");
        for (String str : lineList) {
            if (StrUtil.isNotEmpty(str) && str.contains("-")) {
                String[] array = str.split("---", -1);
                if (array.length == 2) {
                    replaceMap.put(array[0], array[1]);
                } else {
                    System.out.println("异常匹配词:" + str);
                }
            }
        }
        System.out.println("共加载替换字符" + authReplaceMap.size() + "个");
    }


    public static void main(String args[]) {
        String s = "T&h@eŁłf芗塘? il(ü)l—eｔf\uE131i\uE003ećlêdκa《s：d—fμgçhèjôkàl <> r;e.s,u(l)t[s]a\"v-e : È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç·1\uE0032\uE0043\uE1314\uE36B5\uE5846\uE5E47\uE5E58\uE4D39\uE0E70-=【】、；‘，。/~！@#￥%……&*（）——+{}|：“《》？`1\uE5822\uE1123\uE0124\uE0115\uE0106\uE0097890-=[]\\;',./~!@#$%^&*()_+{}|:\"<>?";
        System.out.println("convertNonAscii: " + convertNonAscii(s));
        // output :
        // The result : E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c
//        String ss = "测试哈哈哈heheh123 ";
//        System.out.println(sort(ss));
//
//        String str1 = "叶尖压力高";
//        String str2 = "系统压力高";
//        str1 = "zhou yuxi";
//        str2 = "zou yuxi";
//        int num = edit(str1, str2);
//        System.out.println(num);
//        System.out.println(edit(str1, str2));
//        System.out.println(similarity(str1, str2, num));
//
//        //测试字符转换
//        String s = " “中，。,. 国”，国‘家’。5：: ： ；；；；4  【】）｝｛？”“‘’";
//        System.out.println(s);
//        System.out.println("中文标点转--" + cToe(s));
//        System.out.println("全角转半角--" + full2Half(s));
//        System.out.println("半角转全角--" + half2Full(s));
//        String xx = "＇";
//        System.out.println(full2Half("全角转半角" + xx));
//        mapInit();
        String author1 = "jia─xz ℓi qq 鲍来强-䁎귀셀ウツaaAA@:  《℃ã○�■  #1️⃣〖Ж┆①ⅰⅱⅲⅳ⑴55&（）(ceshi∩∏";
        System.out.println("作者标准化保留空格处理结果:" + standardizeAuthWithBlank(author1));
        String author2 = "鲍来强？?@①: ：jhkij ；；Ï；；è,é,ê,ë4  【】#";
        System.out.println("期刊标准化有空格:" + standardizeJourWithBlank(author2));
        System.out.println("期刊标准化无空格:" + standardizeJourNoBlank(author2));
        String author3 = "鲍来强？?@①: ：sfsdf ；Ï；；；è,é,ê,ë4  【】#";
        System.out.println(standardizeDefault(author3));
        /**对作者进行相应的处理*/
        System.out.println("标准化作者处理:" + standardizeDefault(s));
        System.out.println("-----标准化作者处理:" + standardizeDefault(convertNonAscii(s)));
        System.out.println("-----标准化作者处理:" + s);
        System.out.println("-----标准化作者处理:" + re(s));


    }
}
